/*
 *          VolumetricLines.glsl
 *
 *
 *      Based on Phillip Rideout's article
 *        "Tron, Volumetric Lines, and Meshless Tubes"
 *
 */

//------------------------------------------------------------------------------



-- Vertex


// IN
layout(location = 0) in vec3 inPosition;
layout(location = 2) in vec3 inNormal;

// OUT
out vec3 vPosition;
out vec3 vNormal;

void main()
{
  vPosition = inPosition;
  vNormal   = inNormal;
}


--


//------------------------------------------------------------------------------



-- Geometry

#extension GL_ARB_separate_shader_objects : enable


// PARAMS
layout(lines_adjacency, invocations=1) in;
layout(triangle_strip, max_vertices=32) out;

// IN
layout(location=0) in vec3 vPosition[4];
layout(location=1) in vec3 vNormal[4];

// OUT
out vec2 gEndPoints[2];
out vec2 gPosition;


// UNIFORM
uniform mat4 uModelViewProjMatrix;
uniform float uRadius = 1.0f;

// 8 corners of the parallepiped
vec4 ppp[8];


void emit()
{
  gPosition = gl_Position.xy / gl_Position.w; 
  EmitVertex();
}

// Emit a quad face of the parallepiped (2 triangles)
void emitFace(int a, int b, int c, int d)
{
  gl_Position = ppp[a]; emit();
  gl_Position = ppp[b]; emit();
  gl_Position = ppp[c]; emit();
  gl_Position = ppp[d]; emit();
  EndPrimitive();
}

void main()
{
  vec3 p0 = vPosition[0];
  vec3 p1 = vPosition[1];
  vec3 p2 = vPosition[2];
  vec3 p3 = vPosition[3];
  
  vec3 n1 = vNormal[1];
  vec3 n2 = vNormal[2];
  
  
  // Segment end points in Screen Space
  vec4 pt;
  pt = uModelViewProjMatrix * vec4( p1, 1.0f);
  gEndPoints[0] = pt.xy / pt.w;  
  pt = uModelViewProjMatrix * vec4( p2, 1.0f);
  gEndPoints[1] = pt.xy / pt.w;
  
  // Segment direction
  vec3 d0 = normalize(p1-p0);
  vec3 d1 = normalize(p2-p1);
  vec3 d2 = normalize(p3-p2);
    
  
  float radius = uRadius;
  vec3 u, v;
  
  u = radius * n1;
  v = radius * cross( n1, normalize(d0+d1));
  ppp[0] = uModelViewProjMatrix * vec4( p1 + u + v, 1.0f);
  ppp[1] = uModelViewProjMatrix * vec4( p1 + u - v, 1.0f);
  ppp[2] = uModelViewProjMatrix * vec4( p1 - u - v, 1.0f);
  ppp[3] = uModelViewProjMatrix * vec4( p1 - u + v, 1.0f);
  
  u = radius * n2;
  v = radius * cross( n2, normalize(d1+d2));
  ppp[4] = uModelViewProjMatrix * vec4( p2 + u + v, 1.0f);
  ppp[5] = uModelViewProjMatrix * vec4( p2 + u - v, 1.0f);
  ppp[6] = uModelViewProjMatrix * vec4( p2 - u - v, 1.0f);
  ppp[7] = uModelViewProjMatrix * vec4( p2 - u + v, 1.0f);
  
  
  // Emit the six faces of the parallepiped
  //emitFace( 0, 1, 3, 2); emitFace( 5, 4, 6, 7);
  emitFace( 4, 5, 0, 1); emitFace( 3, 2, 7, 6);
  emitFace( 0, 3, 4, 7); emitFace( 2, 1, 6, 5);
}


--


//------------------------------------------------------------------------------


-- Fragment

// IN
in vec2 gEndPoints[2];
in vec2 gPosition;

// OUT
layout(location = 0) out vec4 fragColor;


float line_distance(vec2 pt, vec2 a, vec2 b)
{
  float dist = distance(a,b);    
  vec2 v = normalize(b-a);    
  float t = dot( v, pt-a);

  vec2 spinePoint;
  
  if (t > dist) 
    spinePoint = b;
  else if (t > 0.0) 
    spinePoint = a + t*v;
  else 
    spinePoint = a;
  
  return distance( pt, spinePoint);
}

void main()
{
  vec2 x1 = gEndPoints[0];
  vec2 x2 = gEndPoints[1];
  float d = line_distance(gPosition,x1,x2);

  d = 1 - 30.0 * d;
  
  vec3 color = vec3(0.25f , 0.5f, 1.0f);
  gl_FragColor = d*vec4(color, 1.0f);
}
